import {
  computed,
  effectScope,
  onScopeDispose,
  reactive,
  ref,
  shallowRef,
  toValue,
  watch,
} from "vue";
import type { MaybeRef, Ref } from "vue";
import { useElementSize } from "@vueuse/core";
import type { TableDataWithIndex } from "@sa/hooks";
import { useBoolean, useHookTable } from "@sa/hooks";
import { jsonClone } from "@sa/utils";
import type { AxiosResponse } from "axios";
import { useAppStore } from "@/store/modules/app";
import { $t } from "@/locales";
import type { NetoKit } from "@/typings/neto";
import { PaginationProps, PaginationEmits } from "element-plus";

type RemoveReadonly<T> = {
  -readonly [key in keyof T]: T[key];
};

type TableData = UI.TableData;
type GetTableData<A extends UI.TableApiFn> = UI.GetTableData<A>;
type TableColumn<T> = UI.TableColumn<T> & { hide?: boolean | undefined };

// 定义公共响应类型（根据实际结构调整）
type RESTfulResultPagedList<T> = {
  data?: NetoKit.NetoTableResult<T>;
  // 其他公共字段...
};

/**
 * 封装表格查询
 * @param params 查询参数
 * @param fetcher
 * @returns
 */
export async function fetchTableQuery<TQuery, TOut>(
  params: TQuery,
  fetcher: (
    params: TQuery,
  ) => Promise<AxiosResponse<RESTfulResultPagedList<TOut>>>,
): Promise<NetoKit.NetoTableResult<TOut>> {
  try {
    console.log(params);
    const response = await fetcher(params);
    if (response.data?.data) {
      // 直接返回原始数据结构
      return response.data.data;
    }

    throw new Error("查询失败");
  } catch (err) {
    console.error("Fetch error:", err);
    throw err;
  }
}

export function useNetoTable<A extends NetoKit.NetoTableApiFn>(
  config: NetoKit.NetoTableConfig<A>,
) {
  const scope = effectScope();
  const appStore = useAppStore();

  const isMobile = computed(() => appStore.isMobile);
  const { apiFn, apiParams, immediate, size } = config;

  const SELECTION_KEY = '__selection__';

  const EXPAND_KEY = '__expand__';

  const INDEX_KEY = '__index__';
  const {
    loading,
    empty,
    data,
    columns,
    columnChecks,
    reloadColumns,
    getData,
    searchParams,
    updateSearchParams,
    resetSearchParams,
  } = useHookTable<
    A,
    NetoKit.GetTableData<A>,
    TableColumn<NetoKit.TableDataWithIndex<NetoKit.GetTableData<A>>>
  >({
    apiFn,
    apiParams,
    columns: config.columns,
    transformer: (res) => {
      const {
        items = [],
        pageIndex = 1,
        pageSize = 10,
        totalCount = 0,
      } = res || {};

      // Ensure that the size is greater than 0, If it is less than 0, it will cause paging calculation errors.
      const size = pageSize <= 0 ? 10 : pageSize;

      const recordsWithIndex: TableDataWithIndex<NetoKit.GetTableData<A>>[] =
        items?.map((item: any, index: number) => {
          return {
            ...item,
            index: (pageIndex - 1) * size + index + 1,
          };
        }) || [];

      return {
        data: recordsWithIndex,
        pageNum: pageIndex,
        pageSize: size,
        total: totalCount,
      };
    },
    getColumnChecks: cols => {
      const checks: NetoKit.TableColumnCheck[] = [];
      cols.forEach(column => {
        if (column.type === 'selection') {
          checks.push({
            prop: SELECTION_KEY,
            label: $t('common.check'),
            checked: true
          });
        } else if (column.type === 'expand') {
          checks.push({
            prop: EXPAND_KEY,
            label: $t('common.expandColumn'),
            checked: true
          });
        } else if (column.type === 'index') {
          checks.push({
            prop: INDEX_KEY,
            label: $t('common.index'),
            checked: true
          });
        } else {
          checks.push({
            prop: column.prop as string,
            label: column.label as string,
            checked: column.hide ? false : true,
          });
        }
      });

      return checks;
    },
    getColumns: (cols, checks) => {
      // const columnMap = new Map<
      //   string,
      //   NetoKit.TableColumn<NetoKit.TableDataWithIndex<NetoKit.GetTableData<A>>>
      // >();


      const columnMap = new Map<string, NetoKit.TableColumn<NetoKit.TableDataWithIndex<NetoKit.GetTableData<A>>>>();

      cols.forEach(column => {
        if (column.type === 'selection') {
          columnMap.set(SELECTION_KEY, column);
        } else if (column.type === 'expand') {
          columnMap.set(EXPAND_KEY, column);
        } else if (column.type === 'index') {
          columnMap.set(INDEX_KEY, column);
        } else {
          columnMap.set(column.prop as string, column);
        }
      });

      const filteredColumns = checks
        .filter((item) => item.checked)
        .map(
          (check) =>
            columnMap.get(check.prop) as NetoKit.TableColumn<NetoKit.TableDataWithIndex<NetoKit.GetTableData<A>>>,
        );

      return filteredColumns;
    },
    onFetched: async (transformed) => {
      const { pageNum, pageSize, total } = transformed;

      updatePagination({
        currentPage: pageNum,
        pageSize,
        total,
      });
    },
    immediate,
  });

  type TablePaginationConfig = Partial<RemoveReadonly<PaginationProps & PaginationEmits>>;
  const pagination: TablePaginationConfig = reactive({
    pageIndex: 1,
    pageSize: 10,
    pageSizeOptions: [10, 15, 20, 25, 30],
    total: 0,
    onChange: async (pageIndex: number, pageSize: number) => {
      pagination.currentPage = pageIndex;

      updateSearchParams({
        pageIndex,
        pageSize,
      });

      getData();
    },
  });

  // this is for mobile, if the system does not support mobile, you can use `pagination` directly
  const mobilePagination = computed(() => {
    const p: Partial<RemoveReadonly<PaginationProps & PaginationEmits>> = {
      ...pagination,
      pagerCount: isMobile.value ? 3 : 9
    };

    return p;
  });

  function updatePagination(update: Partial<TablePaginationConfig>) {
    Object.assign(pagination, update);
  }

  /**
   * get data by page number
   *
   * @param pageNum the page number. default is 1
   */
  async function getDataByPage(pageNum: number = 1) {
    updatePagination({
      currentPage: pageNum,
    });

    updateSearchParams({
      pageIndex: pageNum,
      pageSize: pagination.pageSize!,
    });

    await getData();
  }

  scope.run(() => {
    watch(
      () => appStore.locale,
      () => {
        reloadColumns();
      },
    );
  });

  onScopeDispose(() => {
    scope.stop();
  });

  /** 用于查询的类型,没有null值 */
  type SearchParams = {
    [K in keyof Parameters<A>[0]]: NonNullable<Parameters<A>[0][K]>;
  };

  type TableSize = "large" | "middle" | "small" | "tiny" | undefined;

  const tableSize = ref<TableSize>(size);
  return {
    loading,
    empty,
    tableSize,
    data,
    columns,
    columnChecks,
    reloadColumns,
    pagination,
    mobilePagination,
    updatePagination,
    getData,
    getDataByPage,
    searchParams: searchParams as SearchParams,
    updateSearchParams,
    resetSearchParams,
  };
}
export function useTableOperate<T extends WithId>(
  data: Ref<T[]>,
  getData: () => Promise<void>,
) {
  const {
    bool: isVisible,
    setTrue: handleOpen,
    setFalse: handleClose,
  } = useBoolean();

  const operateType = ref<UI.TableOperateType>("add");

  function handleAdd() {
    operateType.value = "add";
    handleOpen();
  }

  /** the editing row data */
  const editingData: Ref<T | undefined> = ref();
  const editingId: Ref<T["id"]> = ref(0);

  function handleEdit(id: T["id"]) {
    operateType.value = "edit";
    getEditData(id);
    handleOpen();
  }

  /** the checked row keys of table */
  const checkedRowKeys = ref<string[]>([]);
  /**
   * 获取需要修改的数据
   * @param id
   * @returns
   */
  function getEditData(id: T["id"]) {
    const findItem = data.value.find((item) => item.id === id) || undefined;
    editingData.value = jsonClone(findItem);
    editingId.value = id;
    return editingData.value;
  }





  /** the hook after the batch delete operation is completed */
  async function onBatchDeleted() {
    window.$message?.success($t("common.deleteSuccess"));

    checkedRowKeys.value = [];

    await getData();
  }

  /** the hook after the delete operation is completed */
  async function onDeleted() {
    window.$message?.success($t("common.deleteSuccess"));

    await getData();
  }

  return {
    isVisible,
    handleOpen,
    handleClose,
    operateType,
    handleAdd,
    editingData,
    editingId,
    handleEdit,
    getEditData,
    checkedRowKeys,
    onBatchDeleted,
    onDeleted,
  };
}
export function useTableScroll(scrollX: MaybeRef<number> = 702) {
  const tableWrapperRef = shallowRef<HTMLElement | null>(null);
  const { height: wrapperElHeight } = useElementSize(tableWrapperRef);

  const scrollConfig = computed(() => {
    return {
      y: wrapperElHeight.value - 72,
      x: toValue(scrollX),
      //x: 'max-content'
    };
  });

  return {
    tableWrapperRef,
    scrollConfig,
  };
}

export interface WithId {
  id?: string | number; // 根据实际需求选择类型
}
